package com.my.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.my.apis.article.IArticleClient;
import com.my.apis.schedule.IScheduleClient;
import com.my.common.constans.ScheduleConstants;
import com.my.common.tencentcloud.ImageDetection;
import com.my.common.tencentcloud.TextDetection;
import com.my.common.tess4j.Tess4jClient;
import com.my.file.service.FileStorageService;
import com.my.model.article.dtos.ArticleDto;
import com.my.model.common.dtos.ResponseResult;
import com.my.model.common.enums.AppHttpCodeEnum;
import com.my.model.schedule.dtos.Task;
import com.my.model.schedule.pojos.TaskinfoLogs;
import com.my.model.wemedia.pojos.WmChannel;
import com.my.model.wemedia.pojos.WmNews;
import com.my.model.wemedia.pojos.WmSensitive;
import com.my.model.wemedia.pojos.WmUser;
import com.my.utils.common.SensitiveWordUtil;
import com.my.wemedia.mapper.WmSensitiveMapper;
import com.my.wemedia.service.WmAutoScanService;
import com.my.wemedia.service.WmChannelService;
import com.my.wemedia.service.WmNewsService;
import com.my.wemedia.service.WmUserService;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class WmAutoScanServiceImpl implements WmAutoScanService {
    @Autowired
    private WmNewsService wmNewsService;
    @Autowired
    private TextDetection textDetection;
    @Autowired
    private ImageDetection imageDetection;
    @Autowired
    private IScheduleClient scheduleClient;

    /**
     * 自动审核文章文本及图片
     * @param id
     */
    @Override
    @Async
    public void AutoScanTextAndImage(Integer id,Long taskId) throws Exception {
        log.info("开始进行文章审核...");
        // Thread.sleep(300);    //休眠300毫秒，以保证能够获取到数据库中的数据
        WmNews wmNews = wmNewsService.getById(id);
        if(wmNews == null) {
            throw new RuntimeException("WmAutoScanServiceImpl-文章信息不存在");
        }

        if(wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            //1.提取文章文本及图片
            Map<String,Object> map = getTextAndImages(wmNews);

            //2.检测文本
            //2.1提取文本
            String content = ((StringBuilder) map.get("content")).toString();
            //2.2自管理敏感词过滤
            boolean SHandleResult = handleSensitiveScan(content,wmNews);
            if(!SHandleResult) return;
            //2.3调用腾讯云进行文本检测
            Boolean THandleResult = handleTextScan(content, wmNews);
            if(!THandleResult) return;

            //3.检测图片
            //3.1提取图片
            List<String> imageUrl = (List<String>) map.get("images");
            //3.2调用腾讯云对图片进行检测
            Boolean IHandleResult = handleImageScan(imageUrl, wmNews);
            if(!IHandleResult) return;

            //4，审核成功
            //4.1保存文章
            log.info("检测到文章无违规内容");
            ResponseResult responseResult = saveAppArticle(wmNews);
            if(!responseResult.getCode().equals(200)) {
                throw new RuntimeException("AutoScanTextAndImage--检测失败");
            }

            //4.2回填article_id
            wmNews.setArticleId((Long) responseResult.getData());
            wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
            wmNews.setReason("审核成功");
            wmNewsService.updateById(wmNews);

            //删除数据库中的任务并更新日志
            scheduleClient.updateDb(taskId, ScheduleConstants.EXECUTED);
        }
    }

    /**
     * 提取文章文本及图片信息
     * @param wmNews
     * @return
     */
    private Map<String,Object> getTextAndImages(WmNews wmNews) {
        //存储纯文本
        StringBuilder text = new StringBuilder();

        //存储图片链接
        List<String> imageUrl = new ArrayList<>();

        //1.从文章内容中提取文本及图片
        if(StringUtils.isNotBlank(wmNews.getContent())) {
            List<Map> maps = JSON.parseArray(wmNews.getContent(),Map.class);
            for (Map map : maps) {
                if(map.get("type").equals("text")) {
                    //文本
                    text.append(map.get("value"));
                }
                if(map.get("type").equals("image")) {
                    //图片
                    imageUrl.add((String) map.get("value"));
                }
            }
        }
        //2.从封面中提取图片
        if(StringUtils.isNotBlank(wmNews.getImages())) {
            for (String imageurl : wmNews.getImages().split(",")) {
                imageUrl.add(imageurl);
            }
        }
        //3.结果封装
        Map<String,Object> map = new HashMap<>();
        map.put("content",text);
        map.put("images",imageUrl);

        return map;
    }

    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;
    /**
     * 自管理敏感词过滤
     * @param content
     * @param wmNews
     * @return
     */
    private boolean handleSensitiveScan(String content,WmNews wmNews) {
        boolean flag = true;
        //1.获取所有的敏感词
        List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(Wrappers.<WmSensitive>lambdaQuery().select(WmSensitive::getSensitives));
        List<String> sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());

        //2.初始化敏感词库
        SensitiveWordUtil.initMap(sensitiveList);

        //3.检测文章是否包含敏感词
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if(map.size() > 0) {
            log.info("当前文章存在敏感词：{}",map.keySet());
            flag = false;
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("当前文章存在敏感词"+map.keySet());
            wmNewsService.updateById(wmNews);
        }
        return flag;
    }

    /**
     * 文本检测
     * @param content
     * @param wmNews
     * @return
     */
    private Boolean handleTextScan(String content,WmNews wmNews) throws TencentCloudSDKException {
        log.info("开始检测文章文本内容...");
        boolean flag = true;
        //1.文本为空
        if(StringUtils.isBlank(content) && StringUtils.isBlank(wmNews.getTitle())) {
            return true;
        }
        //2.调用腾讯云对文本进行检测
        JSONObject resultJson = textDetection.greenTextDetection(content + wmNews.getTitle());
        //审核不通过
        if(resultJson.get("Suggestion").equals("Block")) {
            log.warn("文章存在违规文本，审核不成功");
            flag = false;
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("文章存在违规文本，审核不成功");
            wmNewsService.updateById(wmNews);
        }
        //自动审核不确定
        if(resultJson.get("Suggestion").equals("Review")) {
            log.info("文章存在不确定文本");
            flag = false;
            wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
            wmNews.setReason("文章存在不确定文本");
            wmNewsService.updateById(wmNews);
        }
        return flag;
    }

    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private Tess4jClient tess4jClient;
    /**
     * 图片检测
     * @param list
     * @param wmNews
     * @return
     * @throws TencentCloudSDKException
     */
    private Boolean handleImageScan(List<String> list, WmNews wmNews) throws TencentCloudSDKException {
        log.info("开始检测文章图片内容...");
        boolean flag = true;
        //图片信息为空
        if(list.size() == 0) {
            return true;
        }

        //1.图片去重
        List<String> imageList = list.stream().distinct().collect(Collectors.toList());
        //2.调用腾讯云接口逐一检测
        for (String image : imageList) {
            try {
                //敏感词检测
                //1.下载minio图片文件
                byte[] bytes = fileStorageService.downLoadFile(image);

                //2.从byte[]转换为bufferedImage
                ByteArrayInputStream in = new ByteArrayInputStream(bytes);
                BufferedImage imageFile = ImageIO.read(in);

                //3.识别图片文字
                if(imageFile != null) {
                    String result = tess4jClient.doOCR(imageFile);

                    //4.审核图片是否包含敏感词
                    boolean isSensitive = handleSensitiveScan(result,wmNews);
                    if(!isSensitive) {
                        return false;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            //腾讯云图片安全检测
            JSONObject resultJson = imageDetection.greenImageDetection(image);
            //审核不通过
            if(resultJson.get("Suggestion").equals("Block")) {
                log.warn("文章存在违规图片，审核不成功");
                flag = false;
                wmNews.setStatus(WmNews.Status.FAIL.getCode());
                wmNews.setReason("文章存在违规图片，审核不成功");
                wmNewsService.updateById(wmNews);
            }
            //自动审核不确定
            if(resultJson.get("Suggestion").equals("Review")) {
                log.info("文章存在不确定图片");
                flag = false;
                wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
                wmNews.setReason("文章存在不确定图片");
                wmNewsService.updateById(wmNews);
            }
        }
        return flag;
    }

    @Autowired
    private WmChannelService wmChannelService;
    @Autowired
    private WmUserService wmUserService;
    @Resource
    private IArticleClient iArticleClient;
    /**
     * 保存App端文章数据
     * @param wmNews
     * @return
     */
    @Override
    public ResponseResult saveAppArticle(WmNews wmNews) {
        ArticleDto articleDto = new ArticleDto();

        //1.属性拷贝
        BeanUtils.copyProperties(wmNews,articleDto);

        //2.设置文章布局
        articleDto.setLayout(wmNews.getType());

        //3.设置频道信息
        WmChannel channel = wmChannelService.getById(wmNews.getChannelId());
        if(channel != null) {
            articleDto.setChannelName(channel.getName());
        }

        //4.设置作者信息
        articleDto.setAuthorId(wmNews.getUserId().longValue());
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        if(wmUser != null) {
            articleDto.setAuthorName(wmUser.getName());
        }

        //5.设置文章id
        if(wmNews.getArticleId() != null) {
            articleDto.setId(wmNews.getArticleId());
        }

        //6.设置创建时间
        articleDto.setCreatedTime(new Date());

        //7.保存App端文章
        log.info("异步调用保存文章至App端");
        ResponseResult responseResult = null;
        try {
             responseResult = iArticleClient.saveArticle(articleDto);
        } catch (Exception e) {
            responseResult = new ResponseResult(AppHttpCodeEnum.SERVER_ERROR.getCode(),"保存文章至App失败");
        }

        return responseResult;
    }
}
